// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"strings"

	"apiote.xyz/p/szczanieckiej/transformers"

	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"golang.org/x/text/transform"
)

type NlOvapi struct {
	client http.Client
}

func (NlOvapi) getTimezone() *time.Location {
	l, _ := time.LoadLocation("Europe/Amsterdam")
	return l
}

func (NlOvapi) ConvertVehicles() ([]Vehicle, error) {
	return []Vehicle{}, nil
}

func (NlOvapi) GetVersions(_ time.Time, timezone *time.Location) ([]Version, error) {
	versions := []Version{}
	version, err := MakeVersionTimezone("00010101_99991231", timezone)
	if err != nil {
		return nil, err
	}
	version.Link = "https://gtfs.ovapi.nl/nl/gtfs-nl.zip"
	versions = append(versions, version)
	return versions, nil
}

func (NlOvapi) String() string {
	return "nl_ovapi"
}

func (NlOvapi) RealtimeFeeds() map[RealtimeFeedType]string {
	return map[RealtimeFeedType]string{
		TRIP_UPDATES:      "https://gtfs.ovapi.nl/nl/tripUpdates.pb https://gtfs.ovapi.nl/nl/trainUpdates.pb",
		VEHICLE_POSITIONS: "https://gtfs.ovapi.nl/nl/vehiclePositions.pb",
		ALERTS:            "https://gtfs.ovapi.nl/nl/alerts.pb",
	}
}

func (NlOvapi) Transformer() transform.Transformer {
	return transform.Chain(transformers.TransformerFY, transformers.TransformerNL, transformers.TransformerDE, transformers.TransformerFR, transformers.TransformerDA)
}

func (NlOvapi) Name() string {
	return "The Netherlands"
}

func (NlOvapi) Flags() FeedFlags {
	return FeedFlags{
		Headsign:     HeadsignTripHeadsing,
		StopIdFormat: "{{stop_id}}",
		StopName:     "{{stop_name}} [{{stop_code}}]",
		LineName:     "{{route_short_name}}",
	}
}

func (NlOvapi) FeedPrepareZip(path string) error {
	// NOTE fix wrong encoded characters and add ZWJ for German diaeresises
	trips2File, err := os.OpenFile(filepath.Join(path, "trips2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening trips2 file: %w", err)
	}
	defer trips2File.Close()
	w := csv.NewWriter(trips2File)
	err = forEachRowWithHeader(filepath.Join(path, "trips.txt"), func(header []string) error {
		err := w.Write(header)
		if err != nil {
			return fmt.Errorf("while writing header: %w", err)
		} else {
			return nil
		}
	}, func(offset int64, fields map[string]int, record []string) error {
		record[fields["trip_headsign"]] = strings.ReplaceAll(record[fields["trip_headsign"]], "Mönchengladbach", "M"+ZWJ+"önchengladbach")
		record[fields["trip_headsign"]] = strings.ReplaceAll(record[fields["trip_headsign"]], "Lagerlöflaan", "Lagerl"+ZWJ+"öflaan") // FIXME Selma Lagerlöf was actually swedish, not German
		err := w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing record: %w", err)
		} else {
			return nil
		}
	})
	w.Flush()
	err = os.Remove(filepath.Join(path, "trips.txt"))
	if err != nil {
		return fmt.Errorf("while removing trips: %w", err)
	}
	err = os.Rename(filepath.Join(path, "trips2.txt"), filepath.Join(path, "trips.txt"))
	if err != nil {
		return fmt.Errorf("while renaming trips: %w", err)
	}

	stopsFile, err := os.Open(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while opening stops file: %w", err)
	}
	defer stopsFile.Close()
	stops2File, err := os.OpenFile(filepath.Join(path, "stops2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening stops2 file: %w", err)
	}
	defer stops2File.Close()
	r := csv.NewReader(bufio.NewReader(stopsFile))
	w = csv.NewWriter(stops2File)
	header, err := r.Read()
	if err != nil {
		return fmt.Errorf("while reading stops header: %w", err)
	}
	fields := map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing stops header: %w", err)
	}
	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a stop record: %w", err)
		}

		switch record[fields["stop_code"]] {
		case "HA2700":
			fallthrough
		case "HA2957":
			record[fields["stop_name"]] = "Rotterdam, Port Saïdstraat"
		case "HA2102":
			fallthrough
		case "HA2103":
			record[fields["stop_name"]] = "Rotterdam, Selma Lagerlöfweg"
		case "HA2401":
			record[fields["stop_name"]] = "Rotterdam, Caïrostraat"
		case "HA2473":
			fallthrough
		case "HA2496":
			record[fields["stop_name"]] = "Vlaardingen, Verploegh Chasséplein"
		}

		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "›", "ø")
		// FIXME Atatürk was actually Turkish
		record[fields["stop_code"]] = strings.ReplaceAll(record[fields["stop_code"]], "Bürgermeisteramt", "B"+ZWJ+"ürgermeisteramt")
		record[fields["stop_code"]] = strings.ReplaceAll(record[fields["stop_code"]], "Händelstraat", "H"+ZWJ+"ändelstraat")
		record[fields["stop_code"]] = strings.ReplaceAll(record[fields["stop_code"]], "Grünerweg", "Gr"+ZWJ+"ünerweg")
		record[fields["stop_code"]] = strings.ReplaceAll(record[fields["stop_code"]], "Händellaan", "H"+ZWJ+"ändellaan")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Mönchengladbach", "M"+ZWJ+"önchengladbach")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Lagerlöflaan", "Lagerl"+ZWJ+"öflaan") // FIXME Selma Lagerlöf was actually swedish, not German
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Händelstraat", "H"+ZWJ+"ändelstraat")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Händellaan", "H"+ZWJ+"ändellaan")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Bürgermeisteramt", "B"+ZWJ+"ürgermeisteramt")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Tütthees", "T"+ZWJ+"ütthees")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Bahnübergang", "Bahn"+ZWJ+"übergang")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Nütterden", "N"+ZWJ+"ütterden")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Schützenhaus", "Sch"+ZWJ+"ützenhaus")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Mühle", "M"+ZWJ+"ühle")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Grünerweg", "Gr"+ZWJ+"ünerweg")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Brückenkopf", "Br"+ZWJ+"ückenkopf")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Löwe", "L"+ZWJ+"öwe")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Nütterden", "N"+ZWJ+"ütterden")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Donsbrüggen", "Donsbr"+ZWJ+"üggen")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Lückerheide", "L"+ZWJ+"ückerheide")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Gässchen", "G"+ZWJ+"ässchen")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Tüddern", "T"+ZWJ+"üddern")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Süsterseel", "S"+ZWJ+"üsterseel")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Höngen", "H"+ZWJ+"öngen")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Tüddern", "T"+ZWJ+"üddern")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Höfgen", "H"+ZWJ+"öfgen")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Düsseldorf", "D"+ZWJ+"üsseldorf")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Osnabrück", "Osnabr"+ZWJ+"ück")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Schönefeld", "Sch"+ZWJ+"önefeld")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Südkreuz", "S"+ZWJ+"üdkreuz")
		record[fields["stop_name"]] = strings.ReplaceAll(record[fields["stop_name"]], "Dülken", "D"+ZWJ+"ülken")

		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a stop record: %w", err)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while removing stops: %w", err)
	}
	err = os.Rename(filepath.Join(path, "stops2.txt"), filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while renaming stops: %w", err)
	}

	routesFile, err := os.Open(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while opening routes file: %w", err)
	}
	defer routesFile.Close()
	routes2File, err := os.OpenFile(filepath.Join(path, "routes2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening routes2 file: %w", err)
	}
	defer routes2File.Close()
	r = csv.NewReader(bufio.NewReader(routesFile))
	w = csv.NewWriter(routes2File)
	header, err = r.Read()
	if err != nil {
		return fmt.Errorf("while reading routes header: %w", err)
	}
	fields = map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing routes header: %w", err)
	}
	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a route record: %w", err)
		}

		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Mönchengladbach", "M"+ZWJ+"önchengladbach")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Lagerlöflaan", "Lagerl"+ZWJ+"öflaan") // FIXME Selma Lagerlöf was actually swedish, not German
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Händelstraat", "H"+ZWJ+"ändelstraat")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Händellaan", "H"+ZWJ+"ändellaan")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Bürgermeisteramt", "B"+ZWJ+"ürgermeisteramt")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Tütthees", "T"+ZWJ+"ütthees")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Bahnübergang", "Bahn"+ZWJ+"übergang")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Nütterden", "N"+ZWJ+"ütterden")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Schützenhaus", "Sch"+ZWJ+"ützenhaus")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Mühle", "M"+ZWJ+"ühle")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Grünerweg", "Gr"+ZWJ+"ünerweg")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Brückenkopf", "Br"+ZWJ+"ückenkopf")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Löwe", "L"+ZWJ+"öwe")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Nütterden", "N"+ZWJ+"ütterden")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Donsbrüggen", "Donsbr"+ZWJ+"üggen")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Lückerheide", "L"+ZWJ+"ückerheide")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Gässchen", "G"+ZWJ+"ässchen")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Tüddern", "T"+ZWJ+"üddern")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Süsterseel", "S"+ZWJ+"üsterseel")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Höngen", "H"+ZWJ+"öngen")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Tüddern", "T"+ZWJ+"üddern")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Höfgen", "H"+ZWJ+"öfgen")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Düsseldorf", "D"+ZWJ+"üsseldorf")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Osnabrück", "Osnabr"+ZWJ+"ück")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Schönefeld", "Sch"+ZWJ+"önefeld")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Südkreuz", "S"+ZWJ+"üdkreuz")
		record[fields["route_long_name"]] = strings.ReplaceAll(record[fields["route_long_name"]], "Dülken", "D"+ZWJ+"ülken")

		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a route record: %w", err)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while removing routes: %w", err)
	}
	err = os.Rename(filepath.Join(path, "routes2.txt"), filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while renaming routes: %w", err)
	}
	return nil
}

func (NlOvapi) QRInfo() (string, QRLocation, string) {
	return "", QRLocationNone, ""
}
